﻿using System;
using System.Net;
using System.Web;
using System.Web.Mvc;
using System.Text.RegularExpressions;

namespace MvcCms.Service.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public sealed class CleanUrlsAttribute : FilterAttribute, IAuthorizationFilter
    {

        private bool IsCaseDirty(ref string path)
        {
            //make url's be lowercase
            var match = Regex.Match(path, "[A-Z]");
            if (match.Success)
            {
                path = path.ToLower();
                return true;
            }
            return false;
        }

        private bool IsTrailingSlashDirty(ref string path)
        {
            //we only want a trailing slash on the homepage
            if (path.EndsWith("/") && !path.Equals("/"))
            {
                path = path.TrimEnd(new char[] { '/', '/' });
                return true;
            }
            return false;
        }

        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            //yes we could use the url rewrite here http://weblogs.asp.net/scottgu/archive/2010/04/20/tip-trick-fix-common-seo-problems-using-the-url-rewrite-extension.aspx
            //but we want a trailing slash on the homepage but no where else which i suppose could be configured with the above tool
            //but enforcing this here makes at least this available to people who might not be able to install the above tool
            //plus this is a necessity for MvcCms since a trailing slash on an area link will make the urls for the area not work
            //plus if you are using web deoploy the rewrite settings get knocked out when you deploy so..
            //plus ajax methods may get called with camel case for readability and don't need them getting redirected.
            var httpContext = filterContext.HttpContext;
            var path = httpContext.Request.Url.AbsolutePath;
            var doRedirect = false;

            //first if this is a not found let's see if if the aspxerrorpath has a trailing slash, 
            //if so lets take it off and try again
            if (path.Equals("/notfound"))
            {
                if (httpContext.Request.QueryString["aspxerrorpath"] != "" && httpContext.Request.QueryString["aspxerrorpath"] != null)
                {
                    var errorPath = httpContext.Request.QueryString["aspxerrorpath"];
                    if (IsTrailingSlashDirty(ref errorPath))
                    {
                        //no need to go on lets redirect
                        httpContext.Response.StatusCode = 301;
                        httpContext.Response.RedirectLocation = errorPath;
                        httpContext.Response.End();
                    }
                }
            }
            else
            {
                if (IsCaseDirty(ref path))
                {
                    doRedirect = true;
                    IsTrailingSlashDirty(ref path);
                }
                if (!doRedirect)
                {
                    if (IsTrailingSlashDirty(ref path))
                    {
                        doRedirect = true;
                    }
                }
                if (doRedirect)
                {
                    httpContext.Response.StatusCode = 301;
                    httpContext.Response.RedirectLocation = path;
                    httpContext.Response.End();
                }
            }

        }

    }
}